module.exports=new (function(){

    this.getHead=function(){
        var result="";
        result+="var __reflect = (this && this.__reflect) || function (p, c, t) {\n";
        result+="    p.__class__ = c, t ? t.push(c) : t = [c], p.__types__ = p.__types__ ? t.concat(p.__types__) : t;\n";
        result+="};\n";
        result+="var __extends = (this && this.__extends) || (function () {\n";
        result+="    var extendStatics = Object.setPrototypeOf ||\n";
        result+="        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||\n";
        result+="        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };\n";
        result+="    return function (d, b) {\n";
        result+="        extendStatics(d, b);\n";
        result+="        function __() { this.constructor = d; }\n";
        result+="        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\n";
        result+="    };\n";
        result+="})();\n";
        result+="var n;\n";
        result+="(function (n) {\n";
        // result+="    var Message = (function () {\n";
        // result+="        function Message() {\n";
        // result+="           this._autoRecover=true;\n";
        // result+="           this._toPoolTime=0;\n"
        // result+="        }\n";
        // result+="        Message.prototype.encode = function (bytes) {\n";
        // result+="            return null;\n";
        // result+="        };\n";
        // result+="        Message.prototype.decode = function (bytes) {\n";
        // result+="        };\n";
        // result+="        Message.prototype.initialize = function(){};\n";
        // result+="        Message.prototype.reset = function(){\n";
        // result+="           this._autoRecover=true;\n";
        // result+="        };\n";
        // result+="        Object.defineProperty(Message.prototype, 'autoRecover', {\n";
        // result+="            set: function (v) {\n";
        // result+="                this._autoRecover=v;\n";
        // result+="            },\n";
        // result+="            get: function () {\n";
        // result+="                return this._autoRecover;\n";
        // result+="            }\n";
        // result+="        });\n";
        // result+="        Object.defineProperty(Message.prototype, 'toPoolTime', {\n";
        // result+="            set: function (v) {\n";
        // result+="                this._toPoolTime=v;\n";
        // result+="            },\n";
        // result+="            get: function () {\n";
        // result+="                return this._toPoolTime;\n";
        // result+="            }\n";
        // result+="        });\n";
        // result+="        Object.defineProperty(Message.prototype, 'name', {\n";
        // result+="            get: function () {\n";
        // result+="                return this._name;\n";
        // result+="            }\n";
        // result+="        });\n";
        // result+="        return Message;\n";
        // result+="    }());\n";
        // result+="    n.Message = Message;\n";
        // result+=`    __reflect(Message.prototype, "n.Message");\n`;

        // result+="    var MsgPool = (function () {\n";
        // result+="        var _pool={};\n";
        // result+="        function MsgPool() {\n";
        // result+="        }\n";
        // result+="        MsgPool.from = function (msgClazz) {\n";
        // result+="           var name=msgClazz.name;\n";
        // result+="           if(!_pool[name]){\n";
        // result+="              _pool[name]=[];\n";
        // result+="           }\n";
        // result+="           var list=_pool[name];\n";
        // result+="           if(list.length){\n";
        // result+="               return list.pop();\n";
        // result+="           }\n";
        // result+="           return new msgClazz();\n";
        // result+="        };\n";
        // result+="        MsgPool.to = function (msg,reset) {\n";
        // result+="           var name=msg.name;\n";
        // result+="           if(!_pool[name]){\n";
        // result+="               _pool[name]=[];\n";
        // result+="           }\n";
        // result+="           var list=_pool[msg.name];\n";
        // result+="           if(list.indexOf(msg)==-1){\n";
        // result+="               msg.toPoolTime=egret.getTimer();\n";
        // result+="               list.push(msg);\n";
        // result+="           }\n";
        // result+="           if(reset==undefined||reset) msg.reset();\n";
        // result+="        };\n";
        // result+="        MsgPool.destroyExpiredObjects=function(){\n";
        // result+="           var now=egret.getTimer();\n";
        // result+="           for(var name in _pool){\n";
        // result+="               var list=_pool[name];\n";
        // result+="               for(var i=0;i<list.length;i++){\n";
        // result+="                   if(now-list[i].toPoolTime>20000){\n";
        // result+="                       list.splice(i,1);\n";
        // result+="                       i--;\n";
        // result+="                   }\n";
        // result+="               }\n";
        // result+="               if(!list||!list.length){\n";
        // result+="                   _pool[name]=null;\n";
        // result+="                   delete _pool[name];\n";
        // result+="               }\n";
        // result+="           }\n";
        // result+="        };\n";
        // result+="        MsgPool.getPool = function () {\n";
        // result+="           return _pool\n";
        // result+="        };\n";
        // result+="        return MsgPool;\n";
        // result+="    }());\n";
        // result+="    n.MsgPool = MsgPool;\n";
        // result+=`    __reflect(MsgPool.prototype, "n.MsgPool");\n`;

        return result;
    }
    
    this.getMapContentHead=function(){
        var result="";
        result+="    var Map = (function () {\n";
        result+="        function Map() {\n";
        result+="        }\n";
        result+="        Map.initialize = function () {\n";
        result+="        };\n";
        return result;
    }

    this.getMapContent=function(hash){
        var result="";
        // result+="        Map.initialize = function () {\n";
        // result+="            this._messageStrucks = {};\n";
        // for(var name in hash){
        //     result+=`            this._messageStrucks[this.${name.toLocaleUpperCase()}]=n.${name};\n`;
        // }
        // result+="        };\n";
        // result+="        Map.getMessage = function (routeId) {\n";
        // result+="            return this._messageStrucks[routeId];\n";
        // result+="        };\n";
        for(var name in hash){
            result+=`        Map.${name.toLocaleUpperCase()} = ${hash[name]};\n`;
        }
        result+="        return Map;\n";
        return result;
    }

    this.getMapContentEnd=function(){
        var result="";
        result+="    }());\n";
        result+="    n.Map = Map;\n";
        result+=`    __reflect(Map.prototype, "n.Map");\n`;
        return result;
    }

    this.getMessageContentHead=function(name){
        var result="";
        result+=`    var ${name} = (function (_super) {\n`;
        result+=`        __extends(${name}, _super);\n`;
        return result;
    }

    this.getMessageContentEnd=function(name){
        var result="";
        result+=`    }(n.Message));\n`;
        result+=`    n.${name} = ${name};\n`;
        result+=`    __reflect(${name}.prototype, "n.${name}");\n`
        return result;
    }

    this.getEnd=function(){
        return `})(n || (n = {}));`;
    }
    this.getWriteSigle=function(filed,repeated){
        var space=repeated?"      ":"";
        var result='';
         switch(filed.propertyType){
            case 'string':
                if(repeated){
                    result+=space+`            bytes.writeUTF(this.${filed.propertyName}[i]);\n`;
                }else{
                    result+=space+`            bytes.writeUTF(this.${filed.propertyName});\n`;
                }
                break;
            case 'bool':
			case 'boolean':
                if(repeated){
                    result+=space+`            bytes.writeBoolean(this.${filed.propertyName}[i]);\n`;
                }else{
                    result+=space+`            bytes.writeBoolean(this.${filed.propertyName});\n`;
                }
                break;
            case 'byte':
                if(repeated){
                    result+=space+`            bytes.writeByte(this.${filed.propertyName}[i]);\n`;
                }else{
                    result+=space+`            bytes.writeByte(this.${filed.propertyName});\n`;
                }
                break;
            case 'double':
                if(repeated){
                    result+=space+`            bytes.writeDouble(this.${filed.propertyName}[i]);\n`;
                }else{
                    result+=space+`            bytes.writeDouble(this.${filed.propertyName});\n`;
                }
                break;
            case 'float':
                if(repeated){
                    result+=space+`            bytes.writeFloat(this.${filed.propertyName}[i]);\n`;
                }else{
                    result+=space+`            bytes.writeFloat(this.${filed.propertyName});\n`;
                }
                break;
            case 'int32':
            case 'int64':
                if(repeated){
                    result+=space+`            bytes.writeInt(this.${filed.propertyName}[i]);\n`;
                }else{
                    result+=space+`            bytes.writeInt(this.${filed.propertyName});\n`;
                }
                break;
            case 'uin32':
            case 'uint64':
                if(repeated){
                    result+=space+`            bytes.writeUnsignedInt(this.${filed.propertyName}[i]);\n`;
                }else{
                    result+=space+`            bytes.writeUnsignedInt(this.${filed.propertyName});\n`;
                }
                break;
            case 'sint16':
                if(repeated){
                    result+=space+`            bytes.writeShort(this.${filed.propertyName}[i]);\n`;
                }else{
                    result+=space+`            bytes.writeShort(this.${filed.propertyName});\n`;
                }
                break;
            case 'sint32':
            case 'sing64':
                if(repeated){
                    result+=space+`            bytes.writeUnsignedShort(this.${filed.propertyName}[i]);\n`;
                }else{
                    result+=space+`            bytes.writeUnsignedShort(this.${filed.propertyName});\n`;
                }
                break;
            case 'fixed32':
            case 'fixed64':
            case 'sfixed32':
            case 'sfixed64':
                if(repeated){
                    result+=space+`            bytes.writeUnsignedInt(this.${filed.propertyName}[i]);\n`;
                }else{
                    result+=space+`            bytes.writeUnsignedInt(this.${filed.propertyName});\n`;
                }
                break;
            default:
                if(repeated){
                    result+=space+`            var item${filed.propertyType}=this.${filed.propertyName}[i];\n`;
                    result+=space+`            var item${filed.propertyType}Bytes=item${filed.propertyType}.encode(bytes)\n`
                }else{
                    result+=space+`            this.${filed.propertyName}.encode(bytes);\n`;
                }
                
            break;
        }
        return result;
    }
    this.getReadSigle=function(filed,repeated){
        var space=repeated?"      ":"";
        var result='';
        switch(filed.propertyType){
            case 'string':
                if(repeated){
                    result+=space+`            this.${filed.propertyName}.push(bytes.readUTF());\n`;
                }else{
                    result+=space+`            this.${filed.propertyName}=bytes.readUTF();\n`;
                }
                break;
            case 'bool':
			case 'boolean':
                if(repeated){
                    result+=space+`            this.${filed.propertyName}.push(bytes.readBoolean());\n`;
                }else{
                    result+=space+`            this.${filed.propertyName}=bytes.readBoolean();\n`;
                }
                break;
            case 'byte':
                if(repeated){
                    result+=space+`            this.${filed.propertyName}.push(bytes.readByte());\n`;
                }else{
                    result+=space+`            this.${filed.propertyName}=bytes.readByte();\n`;
                }
                break;
            case 'double':
                if(repeated){
                    result+=space+`            this.${filed.propertyName}.push(bytes.readDouble());\n`;
                }else{
                    result+=space+`            this.${filed.propertyName}=bytes.readDouble();\n`;
                }
                break;
            case 'float':
                if(repeated){
                    result+=space+`            this.${filed.propertyName}.push(bytes.readFloat());\n`;
                }else{
                    result+=space+`            this.${filed.propertyName}=bytes.readFloat();\n`;
                }
                break;
            case 'int32':
            case 'int64':
                if(repeated){
                    result+=space+`            this.${filed.propertyName}.push(bytes.readInt());\n`;
                }else{
                    result+=space+`            this.${filed.propertyName}=bytes.readInt();\n`;
                }
                break;
            case 'uin32':
            case 'uint64':
                if(repeated){
                    result+=space+`            this.${filed.propertyName}.push(bytes.readUnsignedInt());\n`;
                }else{
                    result+=space+`            this.${filed.propertyName}=bytes.readUnsignedInt();\n`;
                }
                break;
            case 'sint16':
                if(repeated){
                    result+=space+`            this.${filed.propertyName}.push(bytes.readShort());\n`;
                }else{
                    result+=space+`            this.${filed.propertyName}=bytes.readShort();\n`;
                }
                break;
            case 'sint32':
            case 'sing64':
                if(repeated){
                    result+=space+`            this.${filed.propertyName}.push(bytes.readUnsignedShort());\n`;
                }else{
                    result+=space+`            this.${filed.propertyName}=bytes.readUnsignedShort();\n`;
                }
                break;
            case 'fixed32':
            case 'fixed64':
            case 'sfixed32':
            case 'sfixed64':
                if(repeated){
                    result+=space+`            this.${filed.propertyName}.push(bytes.readUnsignedInt());\n`;
                }else{
                    result+=space+`            this.${filed.propertyName}=bytes.readUnsignedInt();\n`;
                }
                break;
            default:
                if(repeated){
                    result+=space+`            var item${filed.propertyType}=MsgPool.from(${filed.propertyType});\n`;
                    //result+=space+`            var item${filed.propertyType}=new ${filed.propertyType}();\n`;
                    result+=space+`            item${filed.propertyType}.decode(bytes)\n`
                    result+=space+`            this.${filed.propertyName}.push(item${filed.propertyType});\n`
                }else{
                    result+=space+`            this.${filed.propertyName}=new ${filed.propertyType}();\n`;
                    result+=space+`            this.${filed.propertyName}.decode(bytes)\n`
                }
            break;
        }
        return result;
    }

    this.getMessageContent=function(name,fileds){
        var result='';
         result+=`       var name='${name}';\n`;
        result+=`        function ${name}() {\n`;
        result+="           _super.apply(this, arguments);\n";
        result+=`           this._name='${name}';\n`;
        result+=`           return this;\n`;
        for(var filed of fileds){
            if(filed.defaultValue){
                var defaultValue="";
                switch(jsStruct.getType(filed.propertyType)){
                    case "string":
                        defaultValue="'"+filed.defaultValue+"'";
                    break;
                    case "number":
                        defaultValue=filed.defaultValue;
                    break;
                    case "boolean":
                        defaultValue=parseBool(filed.defaultValue);
                    break;
                }
                result+="			this."+filed.propertyName+" = "+defaultValue+";\n";
            }
        }
        result+=`        }\n`;
        result+=`        ${name}.prototype.encode=function(bytes){\n`
        for(var filed of fileds){
            //console.log(filed.propertyType,filed.propertyName);
            if(filed.type=='repeated'){
                result+=`            var total=this.${filed.propertyName}?this.${filed.propertyName}.length:0;\n`
                result+=`            bytes.writeShort(total);\n`
                result+=`            if(total){\n`
                result+=`               for(var i=0;i<total;i++){\n`
                result+=this.getWriteSigle(filed,true);
                result+=`               }\n`
                result+=`            };\n`
            }else{
                result+=this.getWriteSigle(filed,false);
            }
        }
        result+='            return bytes;\n';
        result+=`        };\n`;
        result+=`        ${name}.prototype.decode=function(bytes){\n`;
        for(var filed of fileds){
            if(filed.type=='repeated'){
                result+=`            if(!this.${filed.propertyName}){this.${filed.propertyName}=[]};\n`;
                result+=`            var total=bytes.readShort();\n`
                result+=`            if(total){\n`
                result+=`               while(total--){\n`
                result+=this.getReadSigle(filed,true);
                result+=`               }\n`
                result+=`            };\n`
            }else{
                result+=this.getReadSigle(filed,false);
            }
        }
        result+='        }\n';

        result+=`        ${name}.prototype.reset=function(){\n`;
        for(var filed of fileds){
            if(filed.type=='repeated'){
                result+=`            if(this.${filed.propertyName}){\n`
                result+=`               var total=this.${filed.propertyName}.length;\n`
                result+=`               for(var i=0;i<total;i++){\n`
                result+=`                   var object=this.${filed.propertyName}[i]\n`
                result+=`                   if(object instanceof Message){\n`
                result+=`                       if(object.autoRecover){\n`;
                result+=`                           object.reset();\n`;
                result+=`                           MsgPool.to(object);\n`;
                result+=`                       }\n`;
                result+=`                   }\n`
                result+=`               };\n`;
                result+=`               this.${filed.propertyName}.length=0;\n`;
                result+=`            };\n`;
            }else{
                result+=`            this.${filed.propertyName}=null;\n`;
            }
        }
        result+="            this._autoRecover=true;\n";
        result+='        }\n';

        result+=`        Object.defineProperty(${name}.prototype, 'name', {\n`
        result+='            get: function () {\n'
        result+='                return this._name\n';
        result+='            }\n'
        result+='        })\n';

        result+=`        return ${name};\n`;
        return result;
    }

    this.getType=function(type){
        switch(type){
            case 'string':
                return "string";
			case 'boolean':
            case 'bool':
                return "boolean";
            case 'double':
            case 'float':
            case 'int32':
            case 'uin32':
            case 'int64':
            case 'uint64':
            case 'sint32':
            case 'sing64':
            case 'fixed32':
            case 'fixed64':
            case 'sfixed32':
            case 'sfixed64':
            case 'byte':
                return "number";
        }
        return type;
    }
})()